﻿using System;
using System.Threading;

namespace DZTC.Base32Utility.Core
{
    public class ProgressReporter
    {
        public delegate void ProgressChangedEvent(long value, long max);

        private class EmptyReporter : ProgressReporter
        {
            public override void Report(long delta)
            {
            }
        }

        public static  ProgressReporter None
        {
            get { return new EmptyReporter(); }
        }
      
        private SynchronizationContext SynchronizationContext { get; set; }


        public long MaxValue { get; private set; }
        public long Value { get; private set; }

        public event ProgressChangedEvent ProgressChanged;

        private void OnProgressChanged(long value, long max)
        {
            var handler = ProgressChanged;
            if (handler != null)
            {
                if (SynchronizationContext != null) 
                    SynchronizationContext.Post(_ => handler(value, max), null);
                
                else handler(value, max);
            }
        }


        public void SetMax(long value)
        {
            MaxValue = value;
        }

        public virtual void Report(long value)
        {
            Value = value;
            if (Value > MaxValue || Value < 0)
            {
                throw new ArgumentException("value");
            }

            OnProgressChanged(Value, MaxValue);
        }

        /// <summary>
        /// Initializares new ProgressReporter
        /// </summary>
        /// <param name="sc">
        /// Syncronization context that will be used for event handler invocation. 
        /// If sc is set to null, current context will be captured. 
        /// If current context is not set, event handler will be invoked on thread, that caused event.
        /// </param>
        public  ProgressReporter(SynchronizationContext sc = null)
        {
            SynchronizationContext = sc ?? SynchronizationContext.Current;

            Value = 0;
            SetMax(100);
        }

    }
}
